package deployr.domain;


import static deployr.core.Streams.*;
import static deployr.domain.NotFound.*;
import static java.text.MessageFormat.*;

import java.io.*;
import java.util.*;

import deployr.core.*;

public class Update implements Serializable, IUpdate {

	private static final long serialVersionUID = 2784879282329769228L;

	private final List<IDeliverable> deliverables = new LinkedList<IDeliverable>();

	private final List<IEvent> events = new LinkedList<IEvent>();

	private int index = 0;

	private String projectKey = "";

	private String status = "";

	private Date date = new Date();

	private DiffSummary diff = new DiffSummary(this, "");

	private String checksum = "";

	private final Artifact artifact;

	private final String updateKey;

	public Update(final Artifact artifact, final int index) {
		this.artifact = artifact;
		this.updateKey = makeUpdateKey(getArtifactId(), getVersion(), index);
		this.projectKey = artifact.checksum();
		this.index = index;
		this.date = new Date();
	}

	public Update(Metadata metadata) {
		this(metadata, Integer.parseInt(metadata.get("index")));
	}

	public Update(Metadata metadata, int index) {
		this(new Artifact(metadata.get("groupId"), metadata.get("artifactId"), metadata.get("version")), index);
	}

	public IEvent addEvent(final String name, Date now) {
		status = name;
		final IEvent event = createEvent(name, now);
		events.add(event);
		return event;
	}

	protected IEvent createEvent(final String name, Date now) {
		return new Event(name, now);
	}

	public String getArtifactId() {
		return artifact.artifactId();
	}

	public String getChecksum() {
		return checksum;
	}

	public Date getCreated() {
		return date;
	}

	public Iterable<IDeliverable> deliverables() {
		return deliverables;
	}

	public String getDiffContent() {
		return diff.content();
	}

	public String diffSummary() {
		return diff.summary();
	}

	@Override
	public boolean equals(final Object obj) {
		if (!Update.class.isAssignableFrom(obj.getClass())) return false;
		return ((IUpdate) obj).getUpdateKey().equals(getUpdateKey());
	}

	public Iterable<IEvent> events() {
		return events;
	}

	public String index() {
		return new Integer(index).toString();
	}

	public String getUpdateKey() {
		return updateKey;
	}

	public String getPath() {
		return format("/{0}/{1}/{2}", getArtifactId(), getVersion(), index);
	}

	public Status getStatus() {
		return new Status(status);
	}

	@Override
	public String toString() {
		return projectKey + ":" + index;
	}

	public void updateChecksum(final String checksum) {
		this.checksum = checksum;
		save();
	}

	public void updateDiff(final String diff) {
		this.diff = new DiffSummary(this, diff);
		save();
	}

	protected void save() {
	}

	public String getVersion() {
		return artifact.version();
	}

	public String getProjectKey() {
		return projectKey;
	}

	private String makeUpdateKey(final String artifactId, final String version, final int index) {
		return Checksums.md5(format("{0}:{1}:{2}", artifactId, version, index));
	}

	public IDeliverable findDeliverable(final String name) {
		for (final IDeliverable deliverable : deliverables) {
			if (deliverable.getName().equals(name)) return deliverable;
		}
		return NotFoundDeliverable;
	}
	
	protected void setChecksum(String checksum) {
		this.checksum = checksum;
	}
	
	protected void setDate(Date date) {
		this.date = date;
	}
	
	protected void setDiffContent(String diffContent) {
		this.diff = new DiffSummary(this, diffContent);
	}
	
	protected void setStatus(String status) {
		this.status = status;
	}
	
	@Override
	public IDeliverable addDeliverable(String name, File file) {
		final IDeliverable deliverable = createDeliverable(name, bytes(file));
		deliverables.add(deliverable);
		return deliverable;
	}
	
	@Override
	public IDeliverable addDeliverable(String name, InputStream inputStream) {
		final IDeliverable deliverable = createDeliverable(name, inputStream);
		deliverables.add(deliverable);
		return deliverable;
	}

	private IDeliverable createDeliverable(String name, InputStream inputStream) {
		return new Deliverable(updateKey, name, bytes(inputStream));
	}

	protected IDeliverable createDeliverable(String name, byte[] bytes) {
		return new Deliverable(updateKey, name, bytes);
	}

}